#pragma once

#include <SFML/Graphics.hpp>
#include <cmath>

template<typename T>
class vec2t {
    public:
    T x, y;
    vec2t<T>() {}
    vec2t<T>(sf::Vector2u v) : x((T)v.x), y((T)v.y) {}
    vec2t<T>(sf::Vector2f v) : x((T)v.x), y((T)v.y) {}
    template<typename T2>
    vec2t<T>(vec2t<T2> v) : x((T)v.x), y((T)v.y) {}
    vec2t<T>(T x, T y) : x(x), y(y) {}
    vec2t<T> operator+(vec2t<T> v) const { return vec2t<T>(x + v.x, y + v.y); }
    vec2t<T> & operator+=(vec2t<T> v) { x += v.x; y += v.y; return *this; }
    vec2t<T> operator-() const { return vec2t<T>(-x, -y); }
    vec2t<T> operator-(vec2t<T> v) const { return vec2t<T>(x - v.x, y - v.y); }
    vec2t<T> & operator-=(vec2t<T> v) { x -= v.x; y -= v.y; return *this; }
    vec2t<T> operator*(T k) const { return vec2t<T>(x * k, y * k); }
    vec2t<T> operator*(vec2t<T> v) const { return vec2t<T>(x * v.x, y * v.y); }
    vec2t<T> & operator*=(T k) { x *= k; y *= k; return *this; }
    vec2t<T> & operator*=(vec2t<T> v) { x *= v.x; y *= v.y; return *this; }
    vec2t<double> operator/(T k) const { return vec2t<double>(k == 0 ? INFINITY : (double)x / k, k == 0 ? INFINITY : (double)y / k); }
    vec2t<double> operator/(vec2t<T> v) const { return vec2t<double>(v.x == 0 ? INFINITY : (double)x / v.x, v.y == 0 ? INFINITY : (double)y / v.y); }
    vec2t<T> & operator/=(T k) { x /= k; y /= k; return *this; }
    vec2t<T> & operator/=(vec2t<T> v) { x /= v.x; y /= v.y; return *this; }
    bool operator==(vec2t<T> v) const { return x == v.x && y == v.y; }
    bool operator!=(vec2t<T> v) const { return x != v.x || y != v.y; }
    vec2t<bool> operator<(vec2t<T> v) const { return vec2t<bool>(x < v.x, y < v.y); }
    vec2t<bool> operator<(T c) const { return vec2t<bool>(x < c, y < c); }
    vec2t<bool> operator<=(vec2t<T> v) const { return vec2t<bool>(x <= v.x, y <= v.y); }
    vec2t<bool> operator<=(T c) const { return vec2t<bool>(x <= c, y <= c); }
    vec2t<bool> operator>(vec2t<T> v) const { return vec2t<bool>(x > v.x, y > v.y); }
    vec2t<bool> operator>(T c) const { return vec2t<bool>(x > c, y > c); }
    vec2t<bool> operator>=(vec2t<T> v) const { return vec2t<bool>(x >= v.x, y >= v.y); }
    vec2t<bool> operator>=(T c) const { return vec2t<bool>(x >= c, y >= c); }
    bool any() { return x || y; }
    bool all() { return x && y; }
    T min() { return x < y ? x : y; }
    T max() { return x > y ? x : y; }
    sf::Vector2f sf() { return sf::Vector2f(x, y); }
    sf::Vector2i sf_i() { return sf::Vector2i((int)x, (int)y); }
};

using vec2 = vec2t<double>;
using vec2i = vec2t<int>;

std::basic_ostream<char> & operator<<(std::basic_ostream<char> & s, vec2 v) {
    s << '(' << v.x << ", " << v.y << ')';
    return s;
}

double abs(vec2 v) { return sqrt(v.x * v.x + v.y * v.y); }
vec2 norm(vec2 v) { return v / abs(v); }
vec2 rotate(vec2 v, double a) { return vec2(v.x * cos(a) - v.y * sin(a), v.y * cos(a) + v.x * sin(a)); }
template<typename T>
vec2t<T> min(vec2t<T> v1, vec2t<T> v2) { return vec2t<T>(v1.x < v2.x ? v1.x : v2.x, v1.y < v2.y ? v1.y : v2.y); }
template<typename T>
vec2t<T> max(vec2t<T> v1, vec2t<T> v2) { return vec2t<T>(v1.x > v2.x ? v1.x : v2.x, v1.y > v2.y ? v1.y : v2.y); }
int f2i(double x) { return (int)x - (x < 0); }
vec2i f2i(vec2 v) { return vec2i(f2i(v.x), f2i(v.y)); }
double cross(vec2 v1, vec2 v2) { return v1.x * v2.y - v1.y * v2.x; }
vec2 inv_y(vec2 v) { return vec2(v.x, 1. - v.y); }

double get_intersection(vec2 org1, vec2 v1, vec2 org2, vec2 v2) {
    return cross(org2 - org1, v2) / cross(v1, v2);
}
